package bytestream

import (
	"got/funcs"
	"sync"
)

func NewByteStream(head [4]byte) *ByteStream {
	o := new(ByteStream)
	o.buffer = make([]byte, 0)
	o.head = head[:]
	return o
}

//打包(并进行gzip压缩）
func Pack(head [4]byte, body []byte) []byte {
	body = funcs.EnGzip(body)
	dataLen := len(body)
	s := new(stream)
	//组成数据流
	s.Head = head[:]           //
	s.BodyLen = int32(dataLen) //
	s.Body = body              //
	s.Check = m256(dataLen)    //
	s.Tail = tail(s.Check)     //
	//组成字节码
	packBytes := make([]byte, 0)
	packBytes = append(packBytes, s.Head...)
	packBytes = append(packBytes, funcs.NumberToByte(s.BodyLen)...)
	packBytes = append(packBytes, s.Body...)
	packBytes = append(packBytes, s.Check)
	packBytes = append(packBytes, s.Tail)
	return packBytes
}

//流
type stream struct {
	Head    []byte //头部：4个字节 = 必须自定义
	BodyLen int32  //长度：4个字节 = len(Body)
	Body    []byte //数据：n个字节 = json序列化，并gzip
	Check   byte   //校验：1个字节 = m256
	Tail    byte   //尾部：1个字节 = 255-Check
}

//字节流
type ByteStream struct {
	stream   *stream      //
	buffer   []byte       //数据缓冲区(接收时用)
	succCall func([]byte) //解包成功后回调
	head     []byte
	sync.Mutex
}

//解包成功后的回调
func (this *ByteStream) UnPackCall(call func([]byte)) *ByteStream {
	this.succCall = call
	return this
}

//输入字节流
func (this *ByteStream) WriteStreams(bt []byte) {
	this.buffer = append(this.buffer, bt...)
	for {
		if code := this.parseBytes(); code == 0 {
			//fmt.Println("解码：", this.buffer)
			//fmt.Println("读取", code)
			return
		}
	}
}

//处理字节流,返回0=无需处理，1=需要再次处理
func (this *ByteStream) parseBytes() (code int8) {
	this.Lock()
	defer this.Unlock()
	bufLen := len(this.buffer) //字节流长度
	if bufLen < 8 {
		return 0
	}
	head := this.head
	//无字节流时进行头校验
	if this.stream == nil {
		checkHead := this.buffer[:4]
		if string(checkHead) != string(head[:]) {
			this.buffer = this.buffer[1:]
			return 1
		}
		this.stream = new(stream)
		this.stream.Head = checkHead
		this.buffer = this.buffer[4:]
		var dataLen int32
		funcs.ByteToNumber(this.buffer[:4], &dataLen)
		this.stream.BodyLen = dataLen
		this.buffer = this.buffer[4:]
	}
	bufLen = len(this.buffer)
	if bufLen >= int(this.stream.BodyLen+2) {
		stop := this.stream.BodyLen
		this.stream.Body = this.buffer[:stop]
		this.buffer = this.buffer[stop:]
		this.stream.Check = this.buffer[0]
		this.stream.Tail = this.buffer[1]
		if this.stream.Check == m256(int(this.stream.BodyLen)) && this.stream.Tail == tail(this.stream.Check) {
			body := funcs.DeGzip(this.stream.Body)
			if this.succCall != nil {
				this.succCall(body)
			}
			this.stream = nil
			if len(this.buffer) > 0 {
				return 1
			}
		}
	}
	return 0
}

//尾
func tail(l byte) byte {
	return 255 - l
}

//模256
func m256(l int) byte {
	return byte(l % 256)
}
